Linux中的动态库和静态库(.a.la.so.o) 您所在的位置:网站首页 linux 链接静态库 Linux中的动态库和静态库(.a.la.so.o)

Linux中的动态库和静态库(.a.la.so.o)

2024-07-16 20:29| 来源: 网络整理| 查看: 265

Linux中的动态库和静态库(.a/.la/.so/.o)

原文地址:https://www.cnblogs.com/findumars/p/5421910.html

在windows下,一般可以通过文件的后缀名来识别文件的类型。在Linux下大致上也是可以的。但是要明确的一点是,在linux下,文件的后缀与文件的类型是没有必然的联系的。这只是约定俗称的习惯罢了。

在linux 下进行C/C++开发,一般都是使用的gcc编译器,所以本文的讲解以gcc为主。

.o文件,即目标文件。一般通过.c或者.cpp文件编译而来,相当于VC编译出来的obj文件.so文件,shared object 共享库(对象),相当于windows下的dll。.a文件,archive 归档包,即静态库。其实质是多个.o文件打包的结果,相当于VC下的.lib文件.la文件,libtool archive 文件,是libtool自动生成的共享库文件。

下面对这四种文件进行逐个说明。

C/C++程序编译的过程

先说一下C/C++编译的几个过程。

预处理,展开头文件,宏定义,条件编译处理等。通过gcc -E source.c -o source.i或者cpp source.c生成。编译。这里是一个狭义的编译意义,指的是将预处理后的文件翻译成汇编代码的过程。通过gcc -S source.i生成。默认生成source.s文件。汇编。汇编即将上一步生成的汇编代码翻译成对应的二进制机器码的过程。通过gcc -c source.s来生成source.o文件。链接。链接是将生成目标文件和其引用的各种符号等生成一个完整的可执行程序的过程。链接的时候会进行虚拟内存的重定向操作。

上面四个步骤就是C/C++程序编译的几个基本步骤。前面三个步骤都是很简单,大多时候会合并为一个步骤。只有第四个步骤链接是复杂一点的。很多时候我们编译比较大的项目,报错的往往是在链接的时候缺少某些库,或者某些符号找不到定义,重定义等。

.o文件(目标文件)

.o文件就是C/C++源码编译的结果。即上面所说的C/C++编译过程中的前三步。一般开发中很少将这三步分开来做,通常的做法是一步生成。

这里举个例子,我们来写一个函数int atoi(const char* str)。

头文件atoi.h

.#ifndef ATOI_H .#define ATOI_H int atoi(const char* str); .#endif //! ATOI_H

源文件atoi.c

.#include .#include "atoi.h" int atoi(const char* str) { int ret = 0; if(str != NULL){ sscanf(str,"%d",&ret); } return ret; } 创建atoi.o

直接使用命令gcc -c atoi.c -o atoi.o或gcc -c atoi.c来生成目标文件。 上面我们函数中调用了sscanf这个C标准库中的函数,那么它在.o文件中会记录这个存在,我们可以使用readelf工具来查看一下。

o@Neo-kylin:~/lib_a_so$ ls atoi.c atoi.h o@Neo-kylin:~/lib_a_so$ gcc -c atoi.c o@Neo-kylin:~/lib_a_so$ ll 总用量 20 drwxr-xr-x 2 o o 4096 10月 10 15:11 ./ drwxrwxr-x 5 1000 1000 4096 10月 10 14:32 ../ -rw-rw-r-- 1 o o 140 10月 10 15:07 atoi.c -rw-rw-r-- 1 o o 75 10月 10 15:07 atoi.h -rw-rw-r-- 1 o o 1536 10月 10 15:11 atoi.o o@Neo-kylin:~/lib_a_so$ readelf -s atoi.o Symbol table '.symtab' contains 11 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS atoi.c 2: 0000000000000000 0 SECTION LOCAL DEFAULT 1 3: 0000000000000000 0 SECTION LOCAL DEFAULT 3 4: 0000000000000000 0 SECTION LOCAL DEFAULT 4 5: 0000000000000000 0 SECTION LOCAL DEFAULT 5 6: 0000000000000000 0 SECTION LOCAL DEFAULT 7 7: 0000000000000000 0 SECTION LOCAL DEFAULT 8 8: 0000000000000000 0 SECTION LOCAL DEFAULT 6 9: 0000000000000000 60 FUNC GLOBAL DEFAULT 1 atoi 10: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND __isoc99_sscanf

这就是.o文件了。它保存了编译的时候引用到的符号(函数,全局变量等),这些符号,在链接的时候需要使用到。

使用atoi.o

使用atoi.o的地方有很多,就不一一列举了。这里先不说怎么用,后面生成.a文件的时候用到了。

.a文件(静态库文件)

静态库是多个.o文件的打包的结果,前面已经说过了,其实不一定非要多个文件,一个.o文件也可以打包为.a文件。 这一步使用ar工具来操作。ar工具是用来创建, 修改和提取archives归档文件的工具,具体使用可以看manpages。

ar [emulation options] [-]{dmpqrstx}[abcfilNoPsSuvV] [member-name] [count] archive-file file...

这个工具的作用看起来很简单,但是其是很强大,且参数的设置很复杂的。这里不是为了介绍这个工具,不细说了。

创建atoi.a

我们先使用上面生成的atoi.o文件来生成一个atoi.a文件。

o@Neo-kylin:~/lib_a_so$ ls atoi.c atoi.h atoi.o o@Neo-kylin:~/lib_a_so$ ar -r atoi.a atoi.o ar: creating atoi.a o@Neo-kylin:~/lib_a_so$ ll 总用量 24 drwxr-xr-x 2 o o 4096 10月 10 15:35 ./ drwxrwxr-x 5 1000 1000 4096 10月 10 14:32 ../ -rw-rw-r-- 1 o o 1678 10月 10 15:35 atoi.a -rw-rw-r-- 1 o o 140 10月 10 15:07 atoi.c -rw-rw-r-- 1 o o 75 10月 10 15:07 atoi.h -rw-rw-r-- 1 o o 1536 10月 10 15:11 atoi.o

-r参数的意思是替换已存在的或插入新的文件到archive包中。

说明:上面的参数也可以是ar -cr atoi.a atoi.o

-c的意思是只编译不链接

/******下面的是我参考博主学习的时候的 ************开始* 注意: 1.这里一定要是从.o 文件编译成.a文件,我自己在学习操作的时候直接从.c编译的,虽然编译成功了,也没有报错,但是在链接的时候报错了 这里写图片描述

在网上找了好久才把问题解决

[ ] 2.所要生成的.a文件的名字前三位最好是lib,否则在链接的时候,就可能导致找不到这个库

*下面的是我参考博主学习的时候的********结束************/

使用atoi.a

创建了atoi.a文件后,我们就可以来使用它了。这里我们写一个main函数来调用atoi。

main.c文件

int main() { return atoi("5"); }

这一次我们先把main.c编译为main.o文件。

o@Neo-kylin:~/lib_a_so$ ls atoi.a atoi.c atoi.h atoi.o main.c o@Neo-kylin:~/lib_a_so$ gcc -c main.c o@Neo-kylin:~/lib_a_so$ ls atoi.a atoi.c atoi.h atoi.o main.c main.o

然后使用ld程序来链接main.o和atoi.a

o@Neo-kylin:~/lib_a_so$ ld main.o atoi.a -o main ld: warning: cannot find entry symbol _start; defaulting to 00000000004000b0 atoi.a(atoi.o): In function `atoi': atoi.c:(.text+0x33): undefined reference to `__isoc99_sscanf'`

上面报了一个错误,原因是在atoi函数中使用未定义的引用 __isoc99_sscanf,这个问题我们可以通过链接上libc.a或者libc.so来解决这个问题。通常的情况下,都是链接libc.so来解决的,如果使用glibc的静态库,那么你也必须将你的程序开源,不然这应该算是违反GPL协议的约定。

o@Neo-kylin:~/lib_a_so$ ld main.o atoi.a /lib64/libc.so.6 -o main ld: warning: cannot find entry symbol _start; defaulting to 0000000000400288

这里又报了一个警告,是没有发现_start符号的意思。这是因为没有发现程序主入口点的原因。在C语言中,程序的入口函数是main,但是在汇编中,程序的主入口函数是_start。

这里我们可以把main.c文件中的main函数改为_start函数,然后再编译为main.o再链接就没有问题了。但是这不是正确的做法,这样做虽然使用ld来链接是不会报错了,但是程序是运行不了的。会报错误

o@Neo-kylin:~/lib_a_so$ ld main.o atoi.a /lib64/libc.so.6 -o main o@Neo-kylin:~/lib_a_so$ ./main -bash: ./main: /lib/ld64.so.1: bad ELF interpreter: 没有那个文件或目录

正确的做法是链接上crt0.o、crti.o、crtn.o等很多个文件就行了,不同的机器,需要链接的文件的位置可能不一样。这个参数可能非常长,普通人记不住。 这个是可以怎么得到呢?我肯定不知道这些文件都在什么位置,但是gcc编译环境知道,我们可以使用gcc来获取。

o@Neo-kylin:~/lib_a_so$ gcc -v -o main main.o atoi.a 使用内建 specs。 目标:x86_64-redhat-linux 配置为:../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable-libjava-multilib --with-ppl --with-cloog --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux 线程模型:posix gcc 版本 4.4.7 20120313 (Red Hat 4.4.7-16) (GCC) COMPILER_PATH=/usr/libexec/gcc/x86_64-redhat-linux/4.4.7/:/usr/libexec/gcc/x86_64-redhat-linux/4.4.7/:/usr/libexec/gcc/x86_64-redhat-linux/:/usr/lib/gcc/x86_64-redhat-linux/4.4.7/:/usr/lib/gcc/x86_64-redhat-linux/:/usr/libexec/gcc/x86_64-redhat-linux/4.4.7/:/usr/libexec/gcc/x86_64-redhat-linux/:/usr/lib/gcc/x86_64-redhat-linux/4.4.7/:/usr/lib/gcc/x86_64-redhat-linux/ LIBRARY_PATH=/usr/lib/gcc/x86_64-redhat-linux/4.4.7/:/usr/lib/gcc/x86_64-redhat-linux/4.4.7/:/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../lib64/:/lib/../lib64/:/usr/lib/../lib64/:/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../:/lib/:/usr/lib/ COLLECT_GCC_OPTIONS='-v' '-o' 'main' '-mtune=generic' /usr/libexec/gcc/x86_64-redhat-linux/4.4.7/collect2 --eh-frame-hdr --build-id -m elf_x86_64 --hash-style=gnu -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o main /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../lib64/crt1.o /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../lib64/crti.o /usr/lib/gcc/x86_64-redhat-linux/4.4.7/crtbegin.o -L/usr/lib/gcc/x86_64-redhat-linux/4.4.7 -L/usr/lib/gcc/x86_64-redhat-linux/4.4.7 -L/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../.. main.o atoi.a -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/x86_64-redhat-linux/4.4.7/crtend.o /usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../lib64/crtn.o

编译之后我们可以来看以下程序运行结果是否正确。

o@Neo-kylin:~/lib_a_so$ ./main o@Neo-kylin:~/lib_a_so$ echo $? 5

结果为5,与预期一致。

/*下面的是我参考博主学习的时候的 *开始************

补充说明:

1.一般的静态库可以放在和工程里面,也可以放在linux为用户准备的目录下/user/local/lib下。这样就不需要链接绝对路径

2.如果.a文件不再指定位置(/user/lib /uer/local/lib ./)加绝对路径的时候就不需要 -L. 和-l参数了,需要指定路径和文件名的全称 这里写图片描述

3.参数含义:

-L.:表示要连接的库在当前目录中 -lmd5.a:编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后 面加上.so来确定库的名称

4.所以通过上面的解释,那么编译的时候直接使用当前文件下的.a文件(前提是.a文件在)应该也是可以的 这里写图片描述

果然可以,执行程序,结果正确

2.所要生成的.a文件的名字前三位最好是lib,否则在链接的时候,就可能导致找不到这个库

******下面的是我参考博主学习的时候的****结束*******************/

### 使用atoi.a

.so文件(共享库文件)

共享库文件和windows下的dll文件(dynamic link library)的概念是一样的,都是在程序运行的时候进行动态链接,供程序调用的。 在linux 下可以使用ldd命令来查看某个可执行文件需要链接哪些共享库(动态库),并可以确定这些要链接的共享库在本机中的位置。

o@Neo-kylin:~/lib_a_so$ ldd main linux-vdso.so.1 => (0x00007fffab1ff000) libc.so.6 => /lib64/libc.so.6 (0x000000305d800000) /lib64/ld-linux-x86-64.so.2 (0x000000305d000000)

这里要说以下动态库的查找路径。对于程序需要链接的动态库xxx.so,如果它在当前目录下有,那么链接当前目录下的。如果没有,那么就链接系统/etc/ld.so.cache(可通过ldconfig来更新)文件中查找xxx.so的路径,如果都没有,那么就会报错啦。

这里应该也可以链接用户目录下的/user/local/lib64文件下的.so文件的

我们在当前目录创建一个libc.so.6文件,然后再使用ldd看一下。

o@Neo-kylin:~/lib_a_so$ touch libc.so.6 && chmod +x libc.so.6 o@Neo-kylin:~/lib_a_so$ ls -l libc.so.6 -rwxrwxr-x 1 o o 0 10月 10 17:15 libc.so.6 o@Neo-kylin:~/lib_a_so$ ldd main ./main: error while loading shared libraries: ./libc.so.6: file too short

可以看到,这时候是链接的当前目录下的libc.so.6这个文件,很可惜,出错了。 其实在链接的时候,我们可以通过-Wl,-rpath=sopath来指定运行时加载动态库的路径。这样做的好处是可以把一些动态库的位置信息不加入到/etc/ld.so.cache中,已经避免和系统已有动态库产生冲突的情况。(例如目标机器的glibc库版本太低,而编译程序的时候使用的高版本的,而出现”libc.so.6: version `GLIBC_2.14’ not found”类似的错误的情况)

注: -Wl: 表示后面的参数将传给link程序ld,gcc编译时候的链接实际上是调用ld进行的.

创建atoi.so

这里还是使用前面创建的atoi.c文件创建atoi.so文件。实际上我们这里创建atoi.so.1文件,文件名后面的.1代表的是版本号。动态库因为使用的时候是动态链接的,而不是直接链接到目标程序文件中的。所以可能同时存在多个版本的情况,一般都会指定版本号。 通常使用libxxx.so.主版本号.副版本号的形式来命名。

o@Neo-kylin:~/lib_a_so$ gcc -shared -o atoi.so.1 atoi.c /usr/bin/ld: /tmp/ccLK0pLC.o: relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC /tmp/ccLK0pLC.o: could not read symbols: Bad value collect2: ld 返回 1 o@Neo-kylin:~/lib_a_so$ gcc -fPIC -shared -o atoi.so.1 atoi.c o@Neo-kylin:~/lib_a_so$ ls atoi.a atoi.c atoi.h atoi.o atoi.so.1 main.c main.o

-share该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号,后面介绍nm工具的时候再说),不用该标志外部程序无法连接。相当于一个可执行文件。 -fPIC表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。

第一次没有指定-fPIC的时候出错了,原因是针对可迁移R_X86_64_32平台,只读数据段’.rodata’不能创建成共享对象,原因是在动态链接动态库的时候,如果没有编译成位置无关代码,那么链接的时候可能因为某些代码的位置具有相关性,而在执行时出现错误。可执行文件在链接时就知道每一行代码、每一个变量会被放到线性地址空间的什么位置,因此这些地址可以都作为常数写到代码里面。对于动态库,只有加载的时候才知道。

如果代码中没有只读数据段,那么就不会有这个问题。例如

o@Neo-kylin:~/lib_a_so$ cat >val.c int a= 100; o@Neo-kylin:~/lib_a_so$ gcc -shared -o val.so val.c 使用atoi.so

使用.so文件的形式和使用.a也差不多,也是使用ld来进行链接。因为这过于复杂,还是使用gcc来做这个操作(实际上gcc也是使用的ld)。

o@Neo-kylin:~/lib_a_so$ gcc -o main main.o atoi.so.1 o@Neo-kylin:~/lib_a_so$ ldd main linux-vdso.so.1 => (0x00007fff56eaf000) atoi.so.1 => not found libc.so.6 => /lib64/libc.so.6 (0x000000305d800000) /lib64/ld-linux-x86-64.so.2 (0x000000305d000000) o@Neo-kylin:~/lib_a_so$ ./main ./main: error while loading shared libraries: atoi.so.1: cannot open shared object file: No such file or directory

上面执行的时候报错,意思是找不到atoi.so.1这个文件。原因是共享库的查找目录没有当前目录,我们可以添加环境变量LD_LIBRARY_PATH来使系统动态载入器 (dynamic linker/loader)在当前目录也查找。

o@Neo-kylin:~/lib_a_so$ export LD_LIBRARY_PATH=. o@Neo-kylin:~/lib_a_so$ ldd main linux-vdso.so.1 => (0x00007fff08fff000) atoi.so.1 => ./atoi.so.1 (0x00007f9ed7ac6000) libc.so.6 => /lib64/libc.so.6 (0x000000305d800000) /lib64/ld-linux-x86-64.so.2 (0x000000305d000000) o@Neo-kylin:~/lib_a_so$ ./main o@Neo-kylin:~/lib_a_so$ echo $? 5

还有一种办法,比添加环境变量更好使,也更具有可移植性,那就是编译的时候指定运行的时候共享库的加载路径。gcc使用-Wl,-rpath=sopath来指定,其中sopath是共享库放置的路径(可以是绝对路径,也可以是相对路径)。

o@Neo-kylin:~/lib_a_so$ gcc -o main main.o -Wl,-rpath=. atoi.so.1 o@Neo-kylin:~/lib_a_so$ ldd main linux-vdso.so.1 => (0x00007fff457ff000) atoi.so.1 => ./atoi.so.1 (0x00007fb946d56000) libc.so.6 => /lib64/libc.so.6 (0x000000305d800000) /lib64/ld-linux-x86-64.so.2 (0x000000305d000000) o@Neo-kylin:~/lib_a_so$ ./main o@Neo-kylin:~/lib_a_so$ echo $? 5

动态库还可以通过dlopen/dlsym等来使用,这里就不介绍了。

/**************下面的是我参考博主学习的时候的 ********************开始**********************************************************************************

1.前面的不加-wl,-rpath参数时和博主的现象一样,加了参数后正常,得到正确的结果了

这里写图片描述

思考:

a.如果该.so文件不在当前路径下是否可以指定路径后正确编译?

这里写图片描述

可以看到这样是可以的,注意-Wl中的w是大写

如果动态库在当前路径下,是否可以直接用gcc编译,而不需要指定路径 这里写图片描述

也是可以的

b.是否可以在编译的时候就加上-wl,-rpath参数,然后后面链接的时候就不需要再加上参数了? 这里写图片描述

看来是不行

c.是否可以将.so文件放在/user/local/lib目录下,效果和放在当前目录下的是一样的?

我的环境是centos7,并不可以

***下面的是我参考博主学习的时候的**********************结束*************************************************************************************/

下面的内容也分享下

.la文件(libtool archive)

以下的内容,参考使用 GNU Libtool 创建库 这里先要说以下libtool这个工具。 libtool是GNU的一个用来解决各个平台创建动态/静态库文件的不同操作的过于复杂的工具。它提供了使用抽象的接口进行动态/静态库的方法。 使用GNU Libtool可以容易的在不同的系统中建立动态链接库。它通过一个称为Libtool库的抽象,隐藏了不同系统之间的差异,给开发人员提供了一致的的接口。对于大部分情况,开发人员甚至不用去查看相应的系统手册,只需要掌握GNU Libtool的用法就可以了。并且,使用 Libtool的Makefile也只需要编写一次就可以在多个系统上使用。

libtool的使用

libtool的使用一般分为以下几个步骤 \1. 创建 Libtool 对象文件 \2. 创建 Libtool 库 \3. 安装 Libtool 库 \4. 使用 Libtool 库 \5. 卸载 Libtool 库

1. 创建 Libtool 对象文件 o@Neo-kylin:~/lib_a_so$ ls atoi.a atoi.c atoi.h main main.c o@Neo-kylin:~/lib_a_so$ libtool --mode=compile gcc -c atoi.c libtool: compile: gcc -c atoi.c -fPIC -DPIC -o .libs/atoi.o libtool: compile: gcc -c atoi.c -o atoi.o >/dev/null 2>&1 o@Neo-kylin:~/lib_a_so$ ls -aR .: . .. atoi.a atoi.c atoi.h atoi.lo atoi.o .libs main main.c main.lo main.o ./.libs: . .. atoi.o libatoi.a libatoi.la libatoi.lai libatoi.so libatoi.so.0 libatoi.so.0.0.0 main.o

创建libtool对象文件的过程,实际上是生成.o、.so、.a文件的过程,同时还生成了一个.lo文件。.lo文件里面描述了两个.o文件的路径。这一步,就已经生成了相应的动态库和静态库。

o@Neo-kylin:~/lib_a_so$ cat atoi.lo # atoi.lo - a libtool object file # Generated by ltmain.sh (GNU libtool) 2.2.6b # # Please DO NOT delete this file! # It is necessary for linking the library. # Name of the PIC object. pic_object='.libs/atoi.o' # Name of the non-PIC object non_pic_object='atoi.o'

其中一个是用于生成静态库的,一个是用于生产动态库的。

2. 创建 Libtool 库 o@Neo-kylin:~/lib_a_so$ libtool --mode=link gcc -o libatoi.la atoi.lo -rpath /home/o/lib_a_so/lib -lc libtool: link: rm -fr .libs/libatoi.a .libs/libatoi.la .libs/libatoi.lai .libs/libatoi.so .libs/libatoi.so.0 .libs/libatoi.so.0.0.0 libtool: link: gcc -shared .libs/atoi.o -lc -Wl,-soname -Wl,libatoi.so.0 -o .libs/libatoi.so.0.0.0 libtool: link: (cd ".libs" && rm -f "libatoi.so.0" && ln -s "libatoi.so.0.0.0" "libatoi.so.0") libtool: link: (cd ".libs" && rm -f "libatoi.so" && ln -s "libatoi.so.0.0.0" "libatoi.so") libtool: link: ar cru .libs/libatoi.a atoi.o libtool: link: ranlib .libs/libatoi.a libtool: link: ( cd ".libs" && rm -f "libatoi.la" && ln -s "../libatoi.la" "libatoi.la" )

注意这里使用atoi.lo作为输入文件,并指定生成的目标文件为libatoi.la。 -rpath选项是指定Libtool将这个库安装到的位置,如果省略了-rpath选项,那么不生成动态链接库。 因为在atoi函数中使用了标准C库函数sscanf,所以带上-lc选项,Libtool 会记住这个依赖关系,后续在使用我们的库时自动的将依赖的库链接进来。

o@Neo-kylin:~/lib_a_so$ ls -aR .: . .. atoi.a atoi.c atoi.h atoi.lo atoi.o libatoi.la .libs main main.c main.lo main.o ./.libs: . .. atoi.o libatoi.a libatoi.la libatoi.lai libatoi.so libatoi.so.0 libatoi.so.0.0.0 main.o

可以看到这次在当前目录下生成了libatoi.la文件,而.libs目录下的那个是一个符号链接,指向当前目录下的这个文件。这其实是一个文本文件,里面的内容比较长,就不贴了。贴几个比较重要的。

o@Neo-kylin:~/lib_a_so$ cat libatoi.la dlname='libatoi.so.0' library_names='libatoi.so.0.0.0 libatoi.so.0 libatoi.so' old_library='libatoi.a' dependency_libs=' -lc' installed=no shouldnotlink=no dlopen='' dlpreopen='' libdir='/home/o/lib_a_so/lib' 3. 安装 Libtool 库 o@Neo-kylin:~/lib_a_so$ libtool --mode=install install -c libatoi.la /home/o/lib_a_so/lib libtool: install: install -c .libs/libatoi.so.0.0.0 /home/o/lib_a_so/libatoi.so.0.0.0 libtool: install: (cd /home/o/lib_a_so && { ln -s -f libatoi.so.0.0.0 libatoi.so.0 || { rm -f libatoi.so.0 && ln -s libatoi.so.0.0.0 libatoi.so.0; }; }) libtool: install: (cd /home/o/lib_a_so && { ln -s -f libatoi.so.0.0.0 libatoi.so || { rm -f libatoi.so && ln -s libatoi.so.0.0.0 libatoi.so; }; }) libtool: install: install -c .libs/libatoi.lai /home/o/lib_a_so/libatoi.la libtool: install: install -c .libs/libatoi.a /home/o/lib_a_so/libatoi.a libtool: install: chmod 644 /home/o/lib_a_so/libatoi.a libtool: install: ranlib /home/o/lib_a_so/libatoi.a libtool: install: warning: remember to run `libtool --finish /home/o/lib_a_so/lib'

上面操作报了一个warning,提示我们去运行 libtool --finish /home/o/lib_a_so/lib,这个操作是使用libtool进行一个正确配置环境变量LD_LIBRARY_PATH、LD_RUN_PATH等的过程。如果不能正常的使用安装好的库,运行这个命令。

ls查看一下,在当前目录生成了 libatoi.a、libatoi.so、libatoi.so.0、libatoi.so.0.0.0这几个文件。

o@Neo-kylin:~/lib_a_so$ ls atoi.a atoi.c atoi.h atoi.lo atoi.o libatoi.a libatoi.la libatoi.so libatoi.so.0 libatoi.so.0.0.0 main main.c 4. 使用 Libtool 库

先编译main.c文件

o@Neo-kylin:~/lib_a_so$ libtool --mode=compile gcc -c main.c libtool: compile: gcc -c main.c -fPIC -DPIC -o .libs/main.o libtool: compile: gcc -c main.c -o main.o >/dev/null 2>&1

然后使用Libtool来进行链接操作。

o@Neo-kylin:~/lib_a_so$ libtool --mode=link gcc -o main main.lo /home/o/lib_a_so/libatoi.la libtool: link: warning: library `/home/o/lib_a_so/libatoi.la' was moved. libtool: link: warning: library `/home/o/lib_a_so/libatoi.la' was moved. libtool: link: gcc -o main .libs/main.o /home/o/lib_a_so/libatoi.so -lc -Wl,-rpath -Wl,/home/o/lib_a_so -Wl,-rpath -Wl,/home/o/lib_a_so

从上面的输出可以看到,实际上它还是调用的gcc来进行的操作,但是它添加了选项-lc,这就是Libtool做的事情之一,它会解决依赖的问题。

o@Neo-kylin:~/lib_a_so$ ls atoi.a atoi.h atoi.o libatoi.la libatoi.so.0 main main.lo atoi.c atoi.lo libatoi.a libatoi.so libatoi.so.0.0.0 main.c main.o o@Neo-kylin:~/lib_a_so$ ./main o@Neo-kylin:~/lib_a_so$ echo $? 5

上面的操作默认使用的动态库,可以使用-static-libtool-libs选项来指定使用静态库。

o@Neo-kylin:~/lib_a_so$ ldd main linux-vdso.so.1 => (0x00007fffd3bff000) libatoi.so.0 => /home/o/lib_a_so/libatoi.so.0 (0x00007f984bdd0000) libc.so.6 => /lib64/libc.so.6 (0x000000305d800000) /lib64/ld-linux-x86-64.so.2 (0x000000305d000000)

使用-static-libtool-libs选项重新生成。

o@Neo-kylin:~/lib_a_so$ libtool --mode=link gcc -o main main.lo /home/o/lib_a_so/libatoi.la -static-libtool-libs libtool: link: warning: library `/home/o/lib_a_so/libatoi.la' was moved. libtool: link: warning: library `/home/o/lib_a_so/libatoi.la' was moved. libtool: link: gcc -o main .libs/main.o /home/o/lib_a_so/libatoi.a -lc

已经不不需要libatoi.so.0了

o@Neo-kylin:~/lib_a_so$ ldd main linux-vdso.so.1 => (0x00007fff1f3ac000) libc.so.6 => /lib64/libc.so.6 (0x000000305d800000) /lib64/ld-linux-x86-64.so.2 (0x000000305d000000) 5. 卸载 Libtool 库

这是对安装操作的反操作,会删除安装的所有库文件。

o@Neo-kylin:~/lib_a_so$ libtool --mode=uninstall rm /home/o/lib_a_so/libatoi.la libtool: uninstall: rm /home/o/lib_a_so/libatoi.la /home/o/lib_a_so/libatoi.so.0.0.0 /home/o/lib_a_so/libatoi.so.0 /home/o/lib_a_so/libatoi.so /home/o/lib_a_so/libatoi.a

http://www.cnblogs.com/oloroso/p/4874801.html



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有